<?php
/**
 * Gestión de archivos de configuración de bases de datos.
 *
 * @author Matías Mirabelli <project@moyrax.com>
 *
 * @package Kingorm
 */
class MappingController
{
	public static $ormBasePath;

	public $relations    = array();

	public $classMapping = array();

	public $operations   = array();

	public $mappingName  = "";

	private $mappings = null;

	private $xmlParser;

	private $builderPath       = "mapping/builders/";

	private $definitionPath    = "definitions/";

	private $definitionExt = ".xdb";

	private $defaultDefinition = "kingorm";

	private $configDefinition = "config";

	private $configFile       = "config.xml";

	private $configObject     = null;

	private $configObjects    = array (
		"KingormMap", "BaseMap", "CollectionMap", "ConfigSectionMap",
		"ConfigValueMap", "ConfigObjectMap", "IQueryBuilder",
		"BaseQueryBuilder"
	);

	private $classLoader = null;

	private $context = null;


	public function MappingController( $mappingName )
	{
		if ( !$mappingName ) {
			return( null );
		}

		XJConfLoader::load('XJConfFacade');

		$this->xmlParser = new XJConfFacade();
		$this->classLoader = FoghornCoreBean::$classLoader;
		$this->context     = FoghornCoreBean::$configure;

		if ( !isset(self::$ormBasePath) )  {
			self::$ormBasePath = $this->context->kingormRoot;
		}

		foreach( $this->configObjects as $item )
		{
			$this->classLoader->loadClass( $item );
		}

		$this->loadConfiguration();

		// Agrega el archivo predeterminado
		// de definiciones.
		//
		$this->xmlParser->addDefinition(
			$this->makeDefinitionPath( $this->defaultDefinition )
		);

		$this->mappingName = $mappingName;
	}

	/**
	 * Carga un archivo de mapeos.
	 *
	 * @param xmlFilename Ruta de acceso y nombre del archivo de mapeos.
	 */
	public function loadMappingFile( $xmlFilename )
	{
		$this->xmlParser->parse( $xmlFilename );

		$app = $this->xmlParser->getConfigValue("kingorm-mapping");

		$this->mappings = $app;
	}

	/**
	 * Devuelve una de las secciones principales declaradas
	 * en el archivo de definiones global.
	 *
	 * @param $sectionName Nombre de la sección requerida.
	 */
	public function getSection( $sectionName )
	{
		if ( is_array( $this->mappings->$sectionName ) )
		{
			return( $this->mappings->$sectionName );
		}

		return(null);
	}

	/**
	 * Devuelve todos los valores del tipo especificado
	 * que se encuentren dentro de la sección indicada.
	 *
	 * @param $sectionName Nombre de la sección a consultar.
	 * @param $valueName   Nombre del tipo de valores que se devolverán.
	 */
	public function getSectionValues( $sectionName, $valueName )
	{
		$section = $this->getSection( $sectionName );
		$values  = array();

		if( !$section )
			return( null );

		foreach( $section as $item )
		{
			if ( $item instanceof $valueName )
			{
				$values[$item->id] = $item;
			}
		}

		return($values);
	}

	/**
	 * Devuelve un valor a partir del identificador del
	 * mismo, desde una lista de valores.
	 *
	 * @param $values   Lista de valores en la que se buscará.
	 * @param $valueId  Identificador del valor requerido.
	 */
	public function getValueById( $values, $valueId )
	{
		foreach( $values as $item )
		{
			if ( $item->id == $valueId ) {
				return( $item );
			}
		}

		return( null );
	}

	/**
	 * Carga la configuración principal del sistema
	 * de mapeos de base de datos.
	 */
	private function loadConfiguration()
	{
		$this->configObject = array();

		// Agrega las definiciones predeterminadas y
		// carga el archivo de configuración.
		//
		$this->xmlParser->addDefinition(
			$this->makeDefinitionPath( $this->configDefinition )
		);
		$this->xmlParser->parse(
			$this->makeDefinitionPath( $this->configFile, false )
		);

		// Obtiene los elementos con la información de
		// la configuración que se cargará
		//
		$mappingObjects = $this->xmlParser->getConfigValue("mapping-objects");
		$sections = $this->xmlParser->getConfigValue("config-sections");
		$values   = $this->xmlParser->getConfigValue("config-values");

		$this->configObject["mappingObjects"] = $mappingObjects->object;
		$this->configObject["sections"]  = $sections->section;
		$this->configObject["values"]    = $values->value;

		$this->configObject = (object)$this->configObject;

		$this->parseConfiguration();
	}

	/**
	 * Analiza el archivo de configuración y carga todos
	 * los datos asociados al mapeo de objetos.
	 */
	private function parseConfiguration()
	{
		// Carga los objetos de mapeo.
		//
		foreach( $this->configObject->mappingObjects as $item )
		{
			$this->classLoader->loadClass( $item->name );

			$defFile = $this->makeDefinitionPath( $item->name );

			// En el caso que exista un archivo de definiciones para
			// este objeto de mapeo, lo carga anticipadamente.
			//
			if ( is_file( $defFile ) )
			{
				$this->xmlParser->addDefinition( $defFile );
			}

			// Si tiene asociado un Class Builder, carga la clase
			// para que pueda ser utilizada posteriormente.
			//
			if ( isset( $item->builderClass) )
			{
				$this->classLoader->loadClass( $$item->builderClass );
			}
		}
	}

	/**
	 * Crea la ruta completa a un archivo de definiciones,
	 * y le agrega el nombre del archivo para que sea
	 * reconocido como una ruta de acceso válida.
	 *
	 * @param $filename Nombre del archivo de definiciones.
	 */
	private function makeDefinitionPath( $filename, $addExtension = true )
	{
		$defFile = self::$ormBasePath . $this->definitionPath . $filename;

		if ( $addExtension ) {
			$defFile .= $this->definitionExt;
		}

		return( $defFile );
	}
}
?>
